import { Circle, SVG } from '@svgdotjs/svg.js';
import { Vector } from './lib/math';
import { MassPoint } from './lib/phy';
import { distanceForce, multMassPointSystem } from './system';
import { massPointRender, videoRender } from './render';
import { Random } from './lib/random';
import { MultMassPointVideo, multMassPointVideo } from './video';
import { video220 } from './video/v220';

const randomMassPoint = (
    count: number,
    mass: number,
    pRange: number,
    pCenter: Vector,
    vRange: number,
) => {
    const ps: MassPoint[] = [];
    for (let i = 0; i < count; ++i)
        ps.push(new MassPoint(
            mass,
            new Vector(
                Random.in(-pRange, pRange),
                Random.in(-pRange, pRange)).add(pCenter),
            new Vector(
                Random.in(-vRange, vRange),
                Random.in(-vRange, vRange))));
    return ps;
}

type DistanceForce = (r: number) => number;

const limit = (n: number, f: DistanceForce): DistanceForce =>
    r => Math.max(-n, Math.min(n, f(r)));

const kr2 = (k: number): DistanceForce =>
    r => k / (r ** 2);

const vdh = (a: number, ar: number, b: number, br: number): DistanceForce =>
    r => a / (r ** ar) - b / (r ** br);

const vdh_ = (ar: number, br: number, r0: number, fm: number): DistanceForce => {
    const rm = (br * r0 ** (-ar + br) / ar) ** (-1 / (ar - br));
    const c = fm * rm ** (ar + br) / (r0 ** ar * rm ** br - r0 ** br * rm ** ar);
    const a = r0 ** ar * c;
    const b = r0 ** br * c;
    console.log(a, ar, b, br);
    return vdh(a, ar, b, br);
}

const addForce = (fs: DistanceForce[]): DistanceForce =>
    r => fs.reduce((p, f) => p + f(r), 0)


const main = ({
    size = 600,
    massPointCount = 50,
    seed = -1,
    meow = 0,
}: {
    size: number,
    massPointCount: number,
    seed: number,
    meow: number,
}) => {
    if (meow === 220) {
        main2();
        return;
    }

    if (seed < 0)
        Random.init();
    else
        Random.seed = seed;

    const svgElement = SVG().addTo('body').size(size, size);
    const center = new Vector(size / 2, size / 2);
    const system1 = multMassPointSystem(
        randomMassPoint(massPointCount, 1, size / 2, center, 20),
        // distanceForce(limit(1000, kr2(500000))),
        distanceForce(limit(5e6, vdh(5e8, 8, 2e6, 4))),
        // distanceForce(limit(5e6, addForce([
        //     vdh_(12, 3, 3, 1e6),
        //     // kr2(-1e3),
        // ]))),
        0.001,  //秒 迭代步长（越小越精确，越卡）
        size - 10,
        size - 10,
    );

    const render = massPointRender(system1, 0.01, svgElement);
    console.log(system1);
    console.log(render);
}

window.onload = () => {
    const obj: Record<string, number> = {};
    const ps = window.location?.search?.split('?');
    if (ps.length > 1)
        ps[1].split('&').forEach(item => {
            const [k, v] = item.split('=');
            obj[k] = parseInt(v);
        });
    main(obj as any);
    // magicMaker(obj.size);
}

//-----------------------------------------------

const main2 = () => {
    const size = 600;
    const svgElement = SVG().addTo('body').size(size, size);
    const video = video220 as MultMassPointVideo;
    console.log(video);
    videoRender(video, 0.01, svgElement);
}

// --------------------------------------

const createMagicVideo = (vs: Vector[]) => {
    const V = 20;
    const size = 600;
    const total_time = 10;
    const systemM = multMassPointSystem(
        vs.map(p => new MassPoint(1, p, new Vector(Random.in(-V, V), Random.in(-V, V)))),
        distanceForce(limit(5e6, vdh(5e8, 8, 2e6, 4))),
        0.001,
        size - 10,
        size - 10,
    );

    const video = multMassPointVideo(
        systemM,
        0.01,
        total_time,
    );

    video.pList.forEach(vs => vs.reverse());
    console.log(video);
    return video;
}

const magicMaker = (size: number) => {
    const svg = SVG().addTo('body').size(size, size);
    const cs: Circle[] = [];
    svg.click((e: MouseEvent) => {
        if (e.shiftKey) {
            const video = createMagicVideo(cs.map(c => new Vector(c.cx(), c.cy())));
            svg.clear();
            videoRender(video, 0.01, svg);
        }
        else if (e.altKey)
            cs.pop()?.remove();
        else
            cs.push(svg.circle(5).move(e.clientX, e.clientY))
    });
}

[kr2, vdh_, addForce, magicMaker];
